package apigateway.project.core.predicate;


import apigateway.project.commen.config.Rule;
import apigateway.project.core.context.GlobalContext;
import lombok.Getter;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

public class GatewayPredicateChainFactory implements PredicateChainFactory {

    @Override
    public GatewayPredicateChain createChain(Rule rule) {
        return doCreatePredicateChain(rule);
    }

    private GatewayPredicateChain doCreatePredicateChain(Rule rule) {
        GatewayPredicateChain chain = new GatewayPredicateChain();
        List<Predicate> predicates = new ArrayList<>();
        if(rule !=null){
            Map<String, String> predicatesConfigs = rule.getPredicates();
            predicatesConfigs.forEach((predicateId,predicateConfig)->{
                if(predicateId!=null && !predicateId.isEmpty()){
                    Predicate predicateInfo = getPredicateInfo(predicateId);
                    predicates.add(predicateInfo);
                }
            });
        }
        chain.addPredicates(predicates);
        return chain;
    }

    @Override
    public Predicate getPredicateInfo(String predicateId) {
        return predicateIdMap.get(predicateId);
    }


    @Getter
    private static final PredicateChainFactory instance = new GatewayPredicateChainFactory();

    /**
     * 断言存储映射 断言id - 断言
     */
    private Map<String, Predicate> predicateIdMap = new ConcurrentHashMap<>();

    public GatewayPredicateChainFactory(){
        //加载所有断言
        ServiceLoader<Predicate> serviceLoader = ServiceLoader.load(Predicate.class);
        serviceLoader.stream().forEach(predicateProvider -> {
            Predicate predicate = predicateProvider.get();
            String predicateId = null;
            if(predicate != null){
                try {
                    Field field = predicate.getClass().getDeclaredField("PredicateId");
                    field.setAccessible(true);
                    predicateId = (String) field.get(null);
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
                predicateIdMap.put(predicateId,predicate);
            }
        });
    }
}
